<script setup>
import { HSVtoRGB, hue2RGB, rgb2Hex, throttle } from './colorUtil';
import { ref, reactive, watch, nextTick, getCurrentInstance } from 'vue';

const props = defineProps({
    modelValue: {
        type: Boolean,
        default: false,
    },
});

watch(
    () => props.modelValue,
    (val) => {
        colorPickerShow.value = val;
        if (val) {
            open();
        }
    },
);

const emit = defineEmits(['change', 'confirm', 'update:modelValue']);

const colorPickerShow = ref(true);

const hColor = ref('#f00');
const hue = ref(0);

const currentInstance = getCurrentInstance();

let svWidth = 0;
let svHeight = 0;
let svRect = { top: 0, left: 0, width: 0, height: 0 };
let hRect = { top: 0, left: 0, width: 0, height: 0 };
const svPoint = reactive({
    x: 0,
    y: 0,
});

const hPoint = reactive({
    x: 0,
    y: 0,
});

let hHeight = 0;
let hWidth = 0;

const ultimatelyColor = ref('#FF0000');

function getNodeRect(selector) {
    return new Promise((resolve) => {
        const query = uni.createSelectorQuery().in(currentInstance);
        query
            .selectAll(selector)
            .boundingClientRect((res) => {
                resolve(res);
            })
            .exec();
    });
}

const init = async () => {
    const nodes = await getNodeRect('.sv,.hue');
    svRect = nodes[0];
    // // console.log(svRect);
    svHeight = svRect.height;
    svWidth = svRect.width;
    hRect = nodes[1];
    hHeight = hRect.height;
    hWidth = hRect.width;
};

const curChange = (e) => {
    const { x, y } = e.detail;
    hue.value = (x / hWidth) * 360;
    const hrgb = hue2RGB(hue.value);
    hColor.value = hrgb;
    const rgb = HSVtoRGB(
        hue.value,
        svPoint.x / svWidth,
        1 - svPoint.y / svHeight,
    );
    ultimatelyColor.value = rgb2Hex(rgb).toUpperCase();
    emit('change', ultimatelyColor.value);
    // // console.log(rgb);
};
const hClick = (e) => {
    const { x, y } = e.detail;
    hPoint.x = x - hRect.left;
};

//限流函数
const svChangeSetColor = throttle(() => {
    const rgb = HSVtoRGB(
        hue.value,
        svPoint.x / svWidth,
        1 - svPoint.y / svHeight,
    );
    ultimatelyColor.value = rgb2Hex(rgb).toUpperCase();
    emit('change', ultimatelyColor.value);
}, 10);

const svChange = (e) => {
    // // console.log('svChange',e)
    const { x, y, source } = e.detail;
    if (source !== 'touch') {
        return;
    }
    svPoint.x = x;
    svPoint.y = y;
    svChangeSetColor();
};

const svClick = (e) => {
    // console.log(e);
    const { x, y } = e.detail;
    svPoint.x = x - svRect.left;
    svPoint.y = y - svRect.top;

    const rgb = HSVtoRGB(
        hue.value,
        svPoint.x / svWidth,
        1 - svPoint.y / svHeight,
    );
    ultimatelyColor.value = rgb2Hex(rgb).toUpperCase();
};

const open = () => {
    setTimeout(() => {
        nextTick(() => {
            init();
        });
    }, 350);
};

const close = () => {
    emit('update:modelValue', false);
};
const confirm = () => {
    emit('confirm', ultimatelyColor.value);
    emit('update:modelValue', false);
};
</script>

<template>
    <view class="color-picker-wrap" :class="{ open: colorPickerShow }">
        <view class="color-picker">
            <view class="color-picker-sv">
                <view class="color-picker-sv-canvas">
                    <!-- 对比度和明度的矩形 -->
                    <movable-area class="sv-area" @click="svClick">
                        <view class="sv-bg">
                            <view class="sv" :style="{ background: hColor }">
                                <view class="s-mask">
                                    <view class="v-mask"></view>
                                </view>
                            </view>
                        </view>

                        <movable-view
                            :x="svPoint.x"
                            :y="svPoint.y"
                            class="sv-move"
                            @change="svChange"
                            :animation="true"
                            direction="all"
                        ></movable-view>
                    </movable-area>
                </view>
            </view>
            <view class="color-picker-h">
                <view class="color-picker-cur-color-canvas">
                    <movable-area
                        style="width: 100%; height: 100%"
                        @click="hClick"
                    >
                        <view class="hue-bg">
                            <view class="hue"> </view>
                        </view>

                        <movable-view
                            :x="hPoint.x"
                            :y="hPoint.y"
                            class="sv-move"
                            @change="curChange"
                            direction="all"
                        ></movable-view>
                    </movable-area>
                </view>
                <view class="color-picker-cur-color">
                    <view
                        class="cur-color"
                        :style="{ backgroundColor: ultimatelyColor }"
                    ></view>
                    <view class="cur-color-value">{{ ultimatelyColor }}</view>
                </view>
            </view>
        </view>
        <view class="ops-btns">
            <view class="close" @click="close"> 关闭 </view>
            <view>自定义颜色</view>
            <view class="confirm" @click="confirm"> 确定 </view>
        </view>
    </view>
</template>

<style scoped lang="scss">
.color-picker-wrap {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    transition: 300ms;
    transform: translateY(100%);
}
.color-picker-wrap.open {
    transform: translateY(0);
}

.color-picker {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    padding: 20rpx;
    .hue {
        height: 30rpx;
        /* 色相：从左到右依次为 红、黄、绿、青、蓝、洋红，等分渐变 */
        background: linear-gradient(
            to right,
            #f00 0%,
            #ff0 17%,
            #0f0 33%,
            #0ff 50%,
            #00f 67%,
            #f0f 83%,
            #f00 100%
        );
    }
    .s-mask {
        width: 100%;
        height: 100%;
        /* 饱和度x轴实现：从左到右，纯白 >>> 透明的渐变 */
        background: linear-gradient(to right, #fff, rgba(255, 255, 255, 0));
    }
    .v-mask {
        width: 100%;
        height: 100%;
        /* 明度y轴的实现：从下到上，纯黑 >>> 透明的渐变 */
        background: linear-gradient(to top, #000, rgba(0, 0, 0, 0));
    }
    .color-picker-sv {
        width: 100%;
        height: 300rpx;
        display: flex;
        .color-picker-sv-canvas {
            flex: 1;
            display: flex;
            .sv {
                width: 100%;
                height: 100%;
                border-radius: 10rpx;
                overflow: hidden;
            }

            .sv-area {
                width: 100%;
                height: 100%;
            }
            .sv-bg {
                height: 100%;
                padding: 20rpx;
                box-sizing: border-box;
            }
            .sv-move {
                width: 40rpx;
                height: 40rpx;
                box-sizing: border-box;
                border: 4rpx solid #fff;
                border-radius: 40rpx;
                background: #ffffff00;
            }
        }
    }

    .color-picker-h {
        padding: 0 20rpx;
        box-sizing: border-box;
        margin-top: 20rpx;
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: space-between;
        .color-picker-cur-color-canvas {
            flex: 1;
            height: 30rpx;
            transform: translateX(-15rpx);
            .hue {
                width: calc(100% - 30rpx);
                transform: translateX(15rpx);
                border-radius: 30rpx;
                overflow: hidden;
            }
            .sv-move {
                width: 30rpx;
                height: 30rpx;
                background: #00000000;
                border-radius: 30rpx;
                border: 4rpx solid #fff;
                box-sizing: border-box;
            }
        }
        .color-picker-cur-color {
            display: flex;
            align-items: center;
            padding: 14rpx 20rpx;
            margin-left: 20rpx;
            border: 2rpx solid #f2f2f2;
            border-radius: 10rpx;
            .cur-color {
                width: 40rpx;
                height: 40rpx;
                border: 2rpx solid #f2f2f2;
                border-radius: 10rpx;
                margin-right: 10rpx;
            }
            .cur-color-value {
                font-size: 34rpx;
                width: 140rpx;
            }
        }
    }
}

.ops-btns {
    margin-top: 10rpx;
    display: flex;
    justify-content: space-between;
    border-top: 2rpx #f2f2f2 solid;
    padding: 20rpx 40rpx;
    color: #000000;

    .confirm {
        text-align: right;
        color: #007aff;
        .mpInfo-icon {
            font-size: 40rpx;
        }
    }
}
</style>
